package com.wzy.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wzy.base.exception.CustomException;
import com.wzy.content.config.MultipartSupportConfig;
import com.wzy.content.feignclient.MediaServiceClient;
import com.wzy.content.mapper.CourseBaseMapper;
import com.wzy.content.mapper.CourseMarketMapper;
import com.wzy.content.mapper.CoursePublishMapper;
import com.wzy.content.mapper.CoursePublishPreMapper;
import com.wzy.content.model.dto.CourseBaseInfoDto;
import com.wzy.content.model.dto.CoursePreviewDto;
import com.wzy.content.model.dto.TeachplanDto;
import com.wzy.content.model.po.*;
import com.wzy.content.service.CourseBaseInfoService;
import com.wzy.content.service.PreviewPublishService;
import com.wzy.content.service.CourseTeacherService;
import com.wzy.content.service.TeachplanService;
import com.wzy.messagesdk.model.po.MqMessage;
import com.wzy.messagesdk.service.MqMessageService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author wzy
 * @Date 2024/1/18 15:25
 * @description: 课程预览业务实现类
 */
@Slf4j
@Service
public class PreviewPublishServiceImpl implements PreviewPublishService {
    @Autowired
    private CourseBaseInfoService courseBaseInfoService;
    @Autowired
    private TeachplanService teachplanService;
    @Autowired
    private CourseTeacherService courseTeacherService;
    @Autowired
    private CourseMarketMapper courseMarketMapper;
    @Autowired
    private CoursePublishPreMapper coursePublishPreMapper;
    @Autowired
    private CourseBaseMapper courseBaseMapper;
    @Autowired
    private CoursePublishMapper coursePublishMapper;
    @Autowired
    private MqMessageService mqMessageService;
    @Autowired
    private MediaServiceClient mediaServiceClient;
    /**
     * 获取课程预览信息
     * @param courseId 课程id
     * @return
     */
    @Override
    public CoursePreviewDto getCoursePreviewInfo(Long courseId) {
        //获取课程基本信息、营销信息
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfoById(courseId);
        //获取课程计划信息
        List<TeachplanDto> teachPlanInfo = teachplanService.getTeachPlanTree(courseId);
        //查询课程老师相关信息
        List<CourseTeacher> listCourseTeacher = courseTeacherService.getListCourseTeacher(courseId);
        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
        coursePreviewDto.setCourseBase(courseBaseInfo);
        coursePreviewDto.setTeachplans(teachPlanInfo);
        coursePreviewDto.setCourseTeachers(listCourseTeacher);
        return coursePreviewDto;
    }

    /**
     * 课程审核
     * @param companyId 机构id
     * @param courseId 课程id
     */
    @Transactional
    @Override
    public void commitAudit(Long companyId, Long courseId) {
        //获取课程基本信息、营销信息
        CourseBaseInfoDto courseBaseInfo =  courseBaseInfoService.getCourseBaseInfoById(courseId);
        if(courseBaseInfo==null){
            throw new CustomException("课程信息为空");
        }
        //审核状态
        String auditStatus = courseBaseInfo.getAuditStatus();
        if(auditStatus.equals("202003")){
            throw new CustomException("课程已提交请等待审核结束");
        }
        //本机构只允许提交本机构的课程
        if(!courseBaseInfo.getCompanyId().equals(companyId)){
            throw new CustomException("不允许提交其它机构的课程。");
        }

        //课程图片是否填写
        if(StringUtils.isEmpty(courseBaseInfo.getPic())){
            throw new CustomException("提交失败，请上传课程图片");
        }
        //查询课程计划信息
        //获取课程计划信息
        List<TeachplanDto> teachPlanInfo = teachplanService.getTeachPlanTree(courseId);
        if(teachPlanInfo.isEmpty()){
            throw new CustomException("提交失败，还没有添加课程计划");
        }
        //添加课程预发布记录
        CoursePublishPre coursePublishPre = new CoursePublishPre();
        //课程基本信息加部分营销信息
        BeanUtils.copyProperties(courseBaseInfo,coursePublishPre);
        //课程营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);

        //课程营销信息转为json
        String courseMarketJson = JSON.toJSONString(courseMarket);
        //将课程营销信息json数据放入课程预发布表
        coursePublishPre.setMarket(courseMarketJson);

        //课程计划信息转json
        String teachplanTreeString = JSON.toJSONString(teachPlanInfo);
        coursePublishPre.setTeachplan(teachplanTreeString);

        //查询课程老师相关信息
        List<CourseTeacher> listCourseTeacher = courseTeacherService.getListCourseTeacher(courseId);
        //课程老师信息转json
        String courseTeacherString = JSON.toJSONString(listCourseTeacher);
        coursePublishPre.setTeachers(courseTeacherString);


        //设置预发布记录状态,已提交
        coursePublishPre.setStatus("202003");
        //教学机构id
        coursePublishPre.setCompanyId(companyId);
        //提交时间
        coursePublishPre.setCreateDate(LocalDateTime.now());

        CoursePublishPre coursePublishPreUpdate = coursePublishPreMapper.selectById(courseId);
        if(coursePublishPreUpdate == null){
            //添加课程预发布记录
            coursePublishPreMapper.insert(coursePublishPre);
        }else{
            coursePublishPreMapper.updateById(coursePublishPre);
        }
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CourseBase::getId,courseId).set(CourseBase::getAuditStatus,"202003").set(CourseBase::getStatus,"203001");
        courseBaseMapper.update(null,updateWrapper);
    }

    /**
     * 课程发布
     * @param companyId 机构id
     * @param courseId 课程id
     */
    @Transactional
    @Override
    public void publishCourse(Long companyId, Long courseId) {
        //1.查询课程预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        //        1、课程审核通过方可发布。
        if(coursePublishPre==null){
            throw new CustomException("待发布课程为空！");
        }
        //        2、本机构只允许发布本机构的课程。
        if(!coursePublishPre.getCompanyId().equals(companyId)){
            throw new CustomException("本机构只能发布本机构的课程");
        }
        //课程审核状态
        String auditStatus = coursePublishPre.getStatus();
        //审核通过方可发布
        if(!"202004".equals(auditStatus)){
            throw new CustomException("请先提交课程审核，审核通过后才能发布课程！！");
        }
        //保存课程发布信息
        saveCourseInfo(coursePublishPre);
        //保存消息表
        saveCoursePublishMessage(courseId);
        // 删除课程预发布表的对应记录。
        coursePublishPreMapper.deleteById(courseId);
    }

    /**
     * 生成课程静态化文件
     * @param courseId 课程id
     * @return
     */
    @Override
    public File generateCourseHtml(Long courseId) {
        //静态化文件
        File htmlFile = null;
        InputStream inputStream =null;
        FileOutputStream outputStream = null;
        try{
            //配置freeMarker
            Configuration configuration = new Configuration(Configuration.getVersion());
            //加载模板
            //选指定模板路径,classpath下templates下
            //得到classpath路径
            String classpath = this.getClass().getResource("/").getPath();
            configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates/"));
            //设置字符编码
            configuration.setDefaultEncoding("utf-8");

            //指定模板文件名称
            Template template = configuration.getTemplate("course_template.ftl");
            //准备数据
            CoursePreviewDto coursePreviewInfo = this.getCoursePreviewInfo(courseId);

            Map<String, Object> map = new HashMap<>();
            map.put("model", coursePreviewInfo);

            //静态化
            //参数1：模板，参数2：数据模型
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
            //    System.out.println(content);
            //将静态化内容输出到文件中
            inputStream = IOUtils.toInputStream(content);
            //创建静态化文件
            htmlFile = File.createTempFile("course",".html");
            log.debug("课程静态化，生成静态文件:{}",htmlFile.getAbsolutePath());
            //输出流
            outputStream = new FileOutputStream(htmlFile);
            IOUtils.copy(inputStream, outputStream);
        } catch (Exception e) {
            log.error("课程静态化异常:{}",e.toString());
            throw new CustomException("课程静态化异常");
        }finally {
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                if(outputStream!=null){
                    outputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            htmlFile.deleteOnExit();
        }
        return htmlFile;
    }

    /**
     * 将课程静态文件上传到minio
     * @param courseId 课程id
     * @param file 课程页面静态化文件
     */
    @Override
    public void uploadCourseHtml(Long courseId, File file) {
        MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
        String upload = mediaServiceClient.upload(multipartFile, "course/" + courseId + ".html");
        if(upload==null){
            throw new CustomException("上传静态文件异常");
        }
    }

    /**
     * 保存课程发布信息到消息表
     * @param courseId 课程id
     */
    private void saveCoursePublishMessage(Long courseId) {
        MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null);
        if(mqMessage==null){
            throw new CustomException("保存发布课程信息到消息表失败");
        }

    }

    /**
     * 保存课程发布信息
     * @param coursePublishPre 课程预发布表
     */
    private void saveCourseInfo(CoursePublishPre coursePublishPre) {
        //向课程发布表course_publish插入一条记录,记录来源于课程预发布表，如果存在则更新，发布状态为：已发布。
        CoursePublish coursePublish = new CoursePublish();
        BeanUtils.copyProperties(coursePublishPre,coursePublish);
        coursePublish.setStatus("203002");
        CoursePublish coursePublishInfo = coursePublishMapper.selectById(coursePublishPre.getId());
        if(coursePublishInfo==null){
            coursePublishMapper.insert(coursePublish);
        }else{
            coursePublishMapper.updateById(coursePublish);
        }
        //更新课程基本表的发布状态
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CourseBase::getId,coursePublishPre.getId()).set(CourseBase::getStatus,"203002");
        courseBaseMapper.update(null,updateWrapper);
    }

}
